--
-- Lens.hs
-- Copyright (C) 2017 wang <wang@Yet-Another-MBP>
--
-- Distributed under terms of the MIT license.
--

{-# LANGUAGE RankNTypes #-}

import           Data.Functor.Const
import           Data.Functor.Identity

data Position = Position { positionX :: Double, positionY :: Double } deriving (Show)

-- setPositionX, setPositionY :: Double -> Position -> Position
-- setPositionX x p = p { positionX = x }
-- setPositionY y p = p { positionY = y }

data Line = Line { lineStart :: Position, lineEnd :: Position }

type Lens b a = forall f . Functor f => (a -> f a) -> b -> f b


xLens, yLens :: Lens Position Double
xLens f p = (\x -> p { positionX = x }) <$> f (positionX p)
yLens f p = (\y -> p { positionY = y }) <$> f (positionY p)

startLens, endLens :: Lens Line Position
startLens f l = (\s -> l { lineStart = s }) <$> f (lineStart l)
endLens f l = (\s -> l { lineEnd = s }) <$> f (lineEnd l)

over :: ((a -> Identity a) -> b -> Identity b) -> (a -> a) -> b -> b
over lens f = runIdentity . lens (Identity . f)

set :: ((a -> Identity a) -> b -> Identity b) -> a -> b -> b
set lens val = over lens $ const val

view :: ((a -> Const a a) -> b -> Const a b) -> b -> a
view lens = getConst . lens Const
